/*
 * @Author: wuqingchun
 * @Date: 2024-07-01 14:05:57
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-07-01 20:52:11
 */
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>


#include "arq_socket.h"

CARQSocket::CARQSocket(int iRole):
    m_iRole(iRole)
{

}

int32_t CARQSocket::Init(SOCKADDR_UN& refAddr)
{
    int iSock = socket(AF_INET, SOCK_DGRAM, 0);
    if (iSock == -1)
    {
        return -1;
    }

    if (m_iRole == 1)
    {
        if (bind(iSock, (const sockaddr*)&refAddr.stAddrIn, sizeof(refAddr.stAddrIn)) != -1)
        {
            m_LocalAddr = refAddr;
        }
        else
        {
            close(iSock);
            return -1;
        }
    }
    else
    {
        m_PeerAddr = refAddr;
    }

    m_iSock = iSock;

    return 0;
}

int32_t CARQSocket::Send(const void* pData, size_t ulLen)
{
    int32_t iErr = -1;

    if (m_iSock == -1)
    {
        return iErr;
    }

    do
    {
        ssize_t lRet = sendto(m_iSock, pData, ulLen, 0, (const sockaddr*)&m_PeerAddr.stAddrIn, 
                          sizeof(m_PeerAddr.stAddrIn));
        if (lRet == -1)
        {
            if (errno == EINTR)
            {
                // 系统调用被中断，需要重试
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 发送缓冲区满

            }
        }
        else if (lRet < ulLen)
        {
            // UDP 会出现这种情况吗？？
            // 也认为是失败？？
        }
        else
        {
            iErr = 0;
            break;
        }
    } while (1);

    return iErr;
}

ssize_t CARQSocket::Recv(void* pBuf, size_t ulBufLen)
{
    SOCKADDR_UN stPeerAddr;
    socklen_t ulPeerAddrLen = sizeof(stPeerAddr.stAddrIn);
    ssize_t lRet = -1;

    if (m_iSock == -1)
    {
        return -1;
    }

    do
    {
        lRet = recvfrom(m_iSock, pBuf, ulBufLen, 0, (sockaddr*)&m_PeerAddr.stAddrIn, &ulPeerAddrLen);
        if (lRet == -1)
        {
            if (errno == EINTR)
            {
                continue;
            }

            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                break;
            }
        }
        else
        {
            break;
        }
    } while (1);
    
    return lRet;
}
